#ifndef OPENSYNC_H
#define OPENSYNC_H

/*
    当程序需要运行在OpenEmulator中时，需要取消Line 9注释；
    实际在FPGA测试时需要加上该注释
*/

// #define SIM 0
// #include "sim.h"

#include <stdio.h>
#include <stdlib.h>
#include "../../tsmp/include/comp_api.h"
#include "../../tsmp/include/tsmp_addr.h"
#include "../../tsmp/include/tsmp_type.h"




#ifndef SIM
#include <libnet.h>
#include <pcap.h>
#endif

#ifdef SIM
typedef unsigned long long pcap_t;
typedef unsigned long long libnet_t;
#endif

#define SEND_FILE "/home/wu_mao_wen/data/TTE/OpenEmulator/demo/data/data110.txt" 
#define SEND_STATE_FILE "/home/wu_mao_wen/data/TTE/OpenEmulator/demo/data/data210.txt" 
#define RECV_FILE "/home/wu_mao_wen/data/TTE/OpenEmulator/demo/data/data010.txt"
#define CLOCK_PATH "/home/wu_mao_wen/data/TTE/OpenEmulator/demo/data/time.txt"


#define TSMP_ETH_TYPE     0xff01
#define TSMP_CFG_ETH_TYPE 0x1662


#define CLOCK_CYCLE_REG_ADDR 0x00080005
#define LOCAL_CLOCK_REG_ADDR 0x00080002
#define TICK_LENGTH_REG_ADDR 0x00080007
#define PHASE_OFFSET_REG_ADDR 0x00080006
#define SYNC_OK_REG_ADDR 0x00000004

/*conflict with libcomp

typedef unsigned long   u64;
typedef unsigned int    u32;
typedef unsigned short  u16;
typedef unsigned char   u8;
typedef long            s64;
typedef int             s32;
typedef short           s16;
typedef char            s8;

*/
typedef unsigned long   os_time_value; //高 32 bit 是秒，低32 bit 是纳秒



/* Opensync header 16 Bytes Used*/
typedef struct opensync_header {
    u8  timestamp1[8];
    u8  timestamp2[8];
} __attribute__((packed))opensync_header;

/*TSMP header 16 Bytes Used */
typedef struct
{
    u8  dmac[6];
    u8  smac[6];
    u16 eth_type; 		/* 以太网类型  */
    u8  type;	        /* TSMP协议子类型   */
    u8  sub_type;		
}__attribute__((packed))os_tsmp_header;

typedef struct shadow_clock
{
    u64 local_clock_tv;
    u32 local_counter_tv;
    u64 sys_time;
}shadow_clock;

typedef struct tsmp_cfg_pkt
{
    os_tsmp_header     ts_header;
    u16 reg_num;
    u32 base_addr;
    u32 reg1;
    u32 reg2;
    u32 reg3;
    u32 reg4;
}__attribute__((packed))tsmp_cfg_pkt;




/*报文接收发送 API*/

int os_pkt_receive_send_init(u8* net_interface, u8* filter_rule);

u8* os_pkt_receive(u16* pkt_len);

int os_pkt_receive_send_destroy();

int os_pkt_send(u8* pkt, u16 pkt_len);


/*Shawdow Clock*/
void init_shadow_clock(shadow_clock* sc);

void update_shadow_clock(u64 local_clock, u32 local_counter, shadow_clock* sc);

unsigned int get_local_counter_tv(shadow_clock* sc);

unsigned long get_local_clock_tv(shadow_clock* sc);

/*配置本地定时电路*/
int os_cfg_local_clock_cycle (u8* dmac, u32 cycle_duration);

int os_cfg_local_clock(u8* dmac, os_time_value clock_value, os_time_value reference_pit);

int os_cfg_phase_offset(u8* dmac, int offset);

int os_cfg_freq_correction(u8* dmac, u32 frequency_corr);

int os_cfg_freq_corr_cycleduration(u8* dmac, u32 frequency_corr, u32 frequency_corr_cycle);

int os_cfg_sync_mode(u8* dmac, u32 flag);

int os_cfg_node_mid(u8* dmac, u16 mid);

int os_cfg_sync_ok(u8* dmac, u32 flag);

/*报文解析*/
/*opensync header中只有 接收时刻时间戳 有意义 所以直接调用下一个接口即可
int os_pkt_parse(u8 *pkt, opensync_header *os_header);*/

/*将opensync header 的首字节地址传入本函数，返回64位时间戳 （32 bit 秒 + 32 bit 纳秒）*/
os_time_value os_get_receive_pit(u8* pkt);

/*报文构造*/
/*opensync header 生成*/
int os_header_generate(os_time_value dispatch_pit , opensync_header* os_header);

/*Opensync header 添加到标准的同步报文前
int os_header_add (u8* sync_pkt, opensync_header *os_header);*/

/*tsmp 配置报文头 生成*/
int os_tsmp_header_generate(os_tsmp_header* ts_header, u8* dmac, u8* smac, u16 type, u8 subtype, u8 inport);

/*tsmp cfg subutype */
int os_cfg_tsmp_header_generate(os_tsmp_header* ts_header, u8* dmac, u8* smac, u16 type, u8 subtype, u8 rw_type);

/*工具函数*/
/*获取当前系统时间，以微秒为单位*/
u64 get_cur_nano_sec();

/*计算系统时间差值，以微秒为单位*/
u64 get_diff(u64 cur_time, u64 start_time);

/*64bit的数据 网络序转换为主机序*/
// unsigned long long ntohll(unsigned long long val);

/*64bit的数据 主机序转换为网络序*/
// conflict with complib.h
// unsigned long long htonll(unsigned long long val); 

void os_pkt_print(u8* pkt, int len);

#endif